<script>
  let obj = {
    a: {
      b: {
        c: 1,
        cc: {
          dd: {
            f: 'f Val'
          }
        }
      }
    },
    data: {
      v1: 'v1',
      v2: 'v2',
      v3: 'v3'
    }
  }

  console.log(getDeepObjAttr(obj, 'a.b.cc.dd.f'))
  // deep get Object Attribute
  function getDeepObjAttr(obj, deepPath) {
    let paths = deepPath.split('.')
    if (!paths.length) return obj
    let prop,
      targetVal,
      tempObj = obj
    while ((prop = paths.shift()) && paths.length) {
      if (!Reflect.has(tempObj, prop)) {
        return
      }
      tempObj = tempObj[prop]
    }
    return tempObj[prop]
  }


  // setDeepObjAttr(obj, 'a.b.c', '2')
  // setDeepObjAttr(obj, 'a.b.cc.dd.f', 'f Val21')
  // deep set Object Attribute 
  function setDeepObjAttr(model, deepPath, val) {
    // 路径
    let paths = deepPath.split('.')
    // 目标值，后面这个值会存放符合路径下的所有属性
    let targetVal = {}
    // 陆续查找每个对象的prop
    let pathsNew = paths.concat([])
    let prop
    for (let i = paths.length - 1, j = i; i >= 0; i--) {
      prop = paths[i]
      // 最后一层要设定的值
      if (i === j) {
        targetVal[prop] = val
      } else if (i === 0) {
        // 第一层需要直接替换第一个属性
        // this.$set(model, prop, tragetVal) => 需要set将 model中的根属性直接替
        const obj = this.getDeepObjAttr(model, prop);
        Reflect.set(model, prop, Object.assign({}, obj, targetVal))
      } else {
        // 更新每一个层级的值(去除存起来的值)
        let curDeppObj = getDeepObjAttr(model, pathsNew.join('.'))
        // 将当前层级的值存储起来
        Reflect.set(targetVal, prop, Object.assign({}, curDeppObj, targetVal))
        // 删除上个路径存储的值
        Reflect.deleteProperty(targetVal, paths[i + 1])
      }

      // 将处理过的路径去除
      pathsNew.pop()
    }
  }

  // setDeepObjAttr(obj, 'data.v1', 'v11')
  console.log(obj); //sy-log
</script>